package com.ojoin.trade.t0loan_core.web.service.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import com.ojoin.weixin.core.message.model.SendMessage;
import org.activiti.rest.common.api.RequestUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import com.ojoin.trade.common.Constants;
import com.ojoin.trade.common.constdef.IConstDef;
import com.ojoin.trade.common.exception.BusinessException;
import com.ojoin.trade.common.utils.CommonUtils;
import com.ojoin.trade.common.utils.Config;
import com.ojoin.trade.common.utils.FileUploadUtils;
import com.ojoin.trade.common.utils.LogUtils;
import com.ojoin.trade.common.utils.MD5FileUtil;
import com.ojoin.trade.common.utils.SMSSendUtil;
import com.ojoin.trade.common.utils.TimeUtils;
import com.ojoin.trade.common.web.dao.BaseDao;
import com.ojoin.trade.common.web.domain.NotificationTemplate;
import com.ojoin.trade.common.web.domain.TbBillDateInfo;
import com.ojoin.trade.common.web.domain.TbWeekend;
import com.ojoin.trade.common.web.service.TbBillDateInfoService;
import com.ojoin.trade.common.web.service.TbWeekEndService;
import com.ojoin.trade.common.web.service.impl.BaseServiceImpl;
import com.ojoin.trade.common.web.service.impl.NotificationTemplateService;
import com.ojoin.trade.common_core.web.domain.TbMerchantInfo;
import com.ojoin.trade.common_core.web.service.MerchantUserBaseService;
import com.ojoin.trade.supplyloan_core.constdef.ISLConstDef;
import com.ojoin.trade.t0loan_core.utils.ftp.SFtpUtils;
import com.ojoin.trade.t0loan_core.web.dao.TbFtpFileDao;
import com.ojoin.trade.t0loan_core.web.domain.TbFtpFile;
import com.ojoin.trade.t0loan_core.web.domain.TbPosTranscationLog;
import com.ojoin.trade.t0loan_core.web.domain.TbT0LoanFinalApplication;
import com.ojoin.trade.t0loan_core.web.service.FtpFileBaseService;
import com.ojoin.trade.t0loan_core.web.service.PosTranscationLogBaseService;
import com.ojoin.trade.t0loan_core.web.service.T0LoanFinalBaseService;


/**
 * 20160714 修改T1、D1业务不往poslog表中记录明细信息，在ftpFile记录中记录pos交易合计值
 * @author guoting
 *
 */
@Service
public class FtpFileBaseServiceImpl extends BaseServiceImpl<TbFtpFile>
		implements FtpFileBaseService {

	private Logger log = LoggerFactory.getLogger(FtpFileBaseServiceImpl.class);

	@Autowired
	private TbFtpFileDao dao;

	@Override
	protected BaseDao<TbFtpFile> getBaseDao() {
		return dao;
	}

	@Autowired
	private MerchantUserBaseService userService;

	@Autowired
	private PosTranscationLogBaseService poslogService;

	@Autowired
	private TbWeekEndService tbWeekEndService;

	@Autowired
	private TbBillDateInfoService billDateInfoService;
	
	@Autowired
	private T0LoanFinalBaseService loanfinalService;

    @Autowired
    private NotificationTemplateService notificationTemplateService;
    
	public void saveDealAllFtpFile(String localdir)
			throws BusinessException {
		log.info("======================交易明细文件开始处理======================");
		String ftp_outip = Config.getProperty("sysConfig", "ftp.outip");
		SFtpUtils ftp = new SFtpUtils(ftp_outip, IConstDef.FTP_T1_USERNAME,
				IConstDef.FTP_T1_PASSWORD, IConstDef.FTP_OUT_PORT);
		String curDateDir = TimeUtils.getYesterdayDate().replace("-", "");
		String localPath = FileUploadUtils.getDefaultBaseDir() + "/" + localdir +"/" + curDateDir +"/";
		String remotePath = "/download/" + curDateDir + "/";
		ftp.connect();
		
		try {
			Vector v = ftp.listFiles(remotePath);
			if (v.size() > 0) {
				boolean sendmsgflag= true; 
				Iterator it = v.iterator();
				while (it.hasNext()) {
					LsEntry entry = (LsEntry) it.next();
					String eachFileName = entry.getFilename();
					SftpATTRS attrs = entry.getAttrs();
					if (!attrs.isDir() && eachFileName.endsWith(".txt")) {
						TbFtpFile existFile = this.selectDealedFtpFileByName(eachFileName);
						if (existFile != null) {
							sendmsgflag = false;
							log.info("文件" + eachFileName + "已下载并处理，请检查.");
							continue;
						}
						//生成ftpfile下载的初始记录
						TbFtpFile filevo = new TbFtpFile();
						filevo.setFilename(eachFileName);
						this.insert(filevo);
						
						int ftpFileid = filevo.getId();
						
						TbFtpFile updateFileVO = new TbFtpFile();
						updateFileVO.setId(ftpFileid);
						
						String downloandMsg = ftp.downloadFileByMsg(remotePath, eachFileName,
								localPath, eachFileName);
						updateFileVO.setMemo(downloandMsg);
						updateFileVO.setDownloadtime(TimeUtils.getCurDateTime());
						
						if (StringUtils.isEmpty(updateFileVO.getMemo())) {
							updateFileVO.setDownloadflag(IConstDef.FTP_FLAG_DOWNLOADED_SUCCESS);
						} else {
							updateFileVO.setDownloadflag(IConstDef.FTP_FLAG_DOWNLOADED_FAILED);
						}
						this.updateByVO(updateFileVO);
						
						if (IConstDef.FTP_FLAG_DOWNLOADED_SUCCESS == updateFileVO.getDownloadflag()) {
							saveParseFile(ftpFileid, localPath, eachFileName);
						}
					}
				}
				
				if (!CommonUtils.isDev() && sendmsgflag){
					SendMessage.sendMsg(new String[]{"hgc","guoting"},String.format("垫款明细下载处理完成,文件数:%s",v.size()));
//					sendMsg("13521844691", IConstDef.TXFtpFile_DealComplete, v.size());
				}
			}
		} catch (SftpException e) {
			log.error(e.getMessage());
		}
		ftp.disconnect();
		log.info("======================交易明细文件结束处理======================");
		
		
	}
	
	private void sendMsg(String mobile, String type, int filenum) {
		//开发环境不发短信通知
		if (CommonUtils.isDev())
			return;
		
		NotificationTemplate msgtemplate = notificationTemplateService.findByName(type);
		if (msgtemplate == null || StringUtils.isEmpty(msgtemplate.getTemplate())) 
			return;
		
		String msg = msgtemplate.getTemplate().replace("%filenum%", CommonUtils.getString(filenum));
		
		SMSSendUtil.sendMsg(mobile, msg);
	}
	
	/**
	 * 下载单个文件
	 * 
	 * @param remoteFileName
	 *            下载文件名
	 * @param localPath
	 *            本地保存目录(以路径符号结束)
	 * @param localFileName
	 *            保存文件名
	 * @return
	 */
	public boolean saveParseFile(Integer ftpFileid, String localPath, String localFileName) throws BusinessException {
		//更新处理状态及文件汇总信息
		TbFtpFile ftpFileVO = parseCreditFile(localPath, localFileName);
		
		ftpFileVO.setId(ftpFileid);
		ftpFileVO.setDealtime(TimeUtils.getCurDateTime());
		
		if (StringUtils.isEmpty(ftpFileVO.getMemo())) {
			ftpFileVO.setDealflag(IConstDef.FTP_FLAG_DEALED_SUCCESS);
		} else {
			ftpFileVO.setDealflag(IConstDef.FTP_FLAG_DEALED_FAILED);
		}
		this.updateByVO(ftpFileVO);
		
		return true;
	}
	
	@Override
	public int updateDealFlagByID(int id, int dealflag)
			throws BusinessException {
		LogUtils.getT0loanLog().info(
				"更新FTP下载文件的处理状态" + ". id->" + id + ", dealflag->" + dealflag);

		String dealtime = TimeUtils.getCurDateTime();
		return ((TbFtpFileDao) this.getBaseDao()).updateDealFlagByID(id,
				dealflag, dealtime);
	}
	
	@Override
	public int updateByVO(TbFtpFile vo)
			throws BusinessException {
		LogUtils.getT0loanLog().info("更新FTP下载文件记录");
		return ((TbFtpFileDao) this.getBaseDao()).updateByVO(vo);
	}
	
	@Override
	public TbFtpFile selectFtpFileByJoinuseridAndTransdate(
			int joinuserid, String transdate) throws BusinessException {
		LogUtils.getT0loanLog().info("查询商户交易明细合计值记录, " +
				"joinuserid->" + joinuserid + ", transdate->" + transdate + "");
		return ((TbFtpFileDao)this.getBaseDao()).selectFtpFileByJoinuseridAndTransdate(joinuserid, transdate);
	}
	
	private TbFtpFile selectDealedFtpFileByName(String filename)
			throws BusinessException {
		return ((TbFtpFileDao) this.getBaseDao())
				.selectDealedFtpFileByName(filename) ;
	}
	
	// pos交易文件处理
	private TbFtpFile parseCreditFile(String localPath, String localFileName) throws BusinessException {
		long parse_startTime=System.currentTimeMillis();
		
		TbFtpFile ftpFileVO = new TbFtpFile();
		String memo = null;
		
		String[] fileNameStrs = FilenameUtils.getBaseName(localFileName).split("_");
		if (fileNameStrs.length < 2) {
			memo = "文件名：" + localFileName + "不符合规则，请检查.";
			ftpFileVO.setMemo(memo);
			return ftpFileVO;
		}
		
		File file = new File(localPath + localFileName);
		String md5String = null;
		try {
			md5String = MD5FileUtil.getFileMD5String(file);
		} catch (IOException e) {
			memo ="文件" + localFileName + "生成MD5值出错, 请检查.";
			ftpFileVO.setMemo(memo);
			return ftpFileVO;
		}
		ftpFileVO.setMd5(md5String);
		
		String mhtno = fileNameStrs[1];
		TbT0LoanFinalApplication finalvo = loanfinalService.queryTxLoanFinalInfoByMhtno(mhtno);
		if(null==finalvo){
			memo = "商户：" + mhtno + "没有开通垫付业务，请检查.";
			ftpFileVO.setMemo(memo);
			return ftpFileVO;
		}
		ftpFileVO.setIdOfTbMerchantUser(finalvo.getIdOfTbMerchantUser());
		ftpFileVO.setFiletype(finalvo.getOperationType());
		
		HashMap<String, String> poslogno_mchno_map = new HashMap<String, String>();
		BufferedReader bf = null;
		FileInputStream fis = null;
		InputStreamReader isr = null;
		try {
			fis = new FileInputStream(localPath + localFileName);
			isr = new InputStreamReader(fis,Charset.forName(Constants.ENCODING));
			bf = new BufferedReader(isr);
			String eachpos = null;
			long i = 0;
			
			List<TbPosTranscationLog> posloglist = new ArrayList<TbPosTranscationLog>();
			long poslogcount = 0;
			
			long totalrow_poscount = 0;
			long totalrow_transamount = 0;
			long totalrow_transcost = 0;
			long totalrow_clearingamount  = 0;
			
			long loop_poscount = 0;
			long loop_transamount = 0;
			long loop_transcost = 0;
			long loop_clearingamount  = 0;
			
			String transdate = "";
			
			while ((eachpos = bf.readLine()) != null) {
				// 首行为title，直接跳过解析
				if (i++ == 0)
					continue;

				if (eachpos.equals("########") || eachpos.length() == 0)
					break;
				
//				log.info("linestr->" + eachpos);
				String[] posarrays = eachpos.split("\\|");
				// 明细行：0商户号|1聚合商户号|2商户名称|3现在支付订单号|4商户订单号|5交易渠道|6交易类型(01消费,04退货)|7交易时间|8交易金额(分)|9交易手续费(分)|10清算金额(分)
				// 汇总行：0total|1商户名称|2交易记录数(消费+退货)|3交易金额(分:消费-退货)|4商户手续费(分: 消费-退货)|5商户结算金额(分: 消费-退货)
				// 结尾：########

				if (posarrays != null && posarrays.length > 0 && posarrays[0].equals("total")) {
					totalrow_poscount = CommonUtils.getLong(posarrays[2]);
					totalrow_transamount = CommonUtils.getLong(posarrays[3]);
					totalrow_transcost = CommonUtils.getLong(posarrays[4]);
					totalrow_clearingamount  = CommonUtils.getLong(posarrays[5]);
					
					if (totalrow_poscount != loop_poscount) {
						memo = "循环累计交易条数->" + totalrow_poscount + ", 文件合计行易条数->" +loop_poscount + ", 数据不一致，请检查";
					} else if (totalrow_transamount != loop_transamount) {
						memo = "循环累计交易金额->" + totalrow_transamount + ", 文件合计行交易金额->" +loop_transamount + ", 数据不一致，请检查";
					} else if (totalrow_transcost != loop_transcost) {
						memo = "循环累计交易手续费->" + totalrow_transcost + ", 文件合计行交易手续费->" +loop_transcost + ", 数据不一致，请检查";
					} else if (totalrow_clearingamount != loop_clearingamount) {
						memo = "循环累计清算金额->" + totalrow_clearingamount + ", 文件合计行清算金额->" +loop_clearingamount + ", 数据不一致，请检查";
					}
					
					ftpFileVO.setPoslogscount(CommonUtils.getString(loop_poscount));
					ftpFileVO.setTransamount(CommonUtils.getString(loop_transamount));
					ftpFileVO.setTranscost(CommonUtils.getString(loop_transcost));
					ftpFileVO.setClearingamount(CommonUtils.getString(loop_clearingamount));
					break;
				}
				
				//交易单号剔重处理
				if (poslogno_mchno_map.get(posarrays[3]) != null) {
					log.info(posarrays[3] + "重复，自动剔重linestr->" + eachpos);
					continue;
				} else {
					poslogno_mchno_map.put(posarrays[3], posarrays[0]);
				}
				
				if (!mhtno.equals(posarrays[0])) {
					memo = "文件中包含其他商户的pos交易信息，商户号->" + posarrays[0];
					break;
				}
				
				if (StringUtils.isEmpty(transdate)) {
					transdate = TimeUtils.getDateByFullDate(posarrays[7]);
					ftpFileVO.setTransdate(transdate);
				}
				
				if (posarrays[6].equals("01")) {
					loop_transamount += CommonUtils.getLong(posarrays[8]);
				} else if (posarrays[6].equals("04")) {
					loop_transamount -= CommonUtils.getLong(posarrays[8]);
				}
				
				if (posarrays[6].equals("01")) {
					loop_transcost += CommonUtils.getLong(posarrays[9]);
				} else if (posarrays[6].equals("04")) {
					loop_transcost -= CommonUtils.getLong(posarrays[9]);
				}
				
				if (posarrays[6].equals("01")) {
					loop_clearingamount += CommonUtils.getLong(posarrays[10]);
				} else if (posarrays[6].equals("04")) {
					loop_clearingamount -= CommonUtils.getLong(posarrays[10]);
				}
				loop_poscount++;
				
				TbPosTranscationLog poslogvo = new TbPosTranscationLog();
				poslogvo.setIdOfTbMerchantUser(finalvo.getIdOfTbMerchantUser()); 
				poslogvo.setMhtno(posarrays[0]);
				poslogvo.setMhtname(posarrays[2]);
				poslogvo.setPostransno(posarrays[3]);
				poslogvo.setTranstype(posarrays[6]);
				poslogvo.setTransdate(TimeUtils.getDateByFullDate(posarrays[7]));
				poslogvo.setTranstime(TimeUtils.getTimeByFullDate(posarrays[7]));
				poslogvo.setTransamount(posarrays[8]);
				poslogvo.setTranscost(posarrays[9]);
				poslogvo.setClearingamount(posarrays[10]);
				posloglist.add(poslogvo);
				
				// 一万一批，批量新增pos交易日志
				if (posloglist != null && posloglist.size() == 10000) {
					poslogcount += posloglist.size();
					poslogService.insertJDBCBatch(posloglist);
					posloglist.clear();
				}
				
			}

			if (posloglist != null && posloglist.size() > 0) {
				poslogcount += posloglist.size();
				// 剩余不足一万的记录，批量新增pos交易日志
				poslogService.insertJDBCBatch(posloglist);
			}
			log.info("文件：" + localFileName + "，pos交易总条数->" + poslogcount);
			ftpFileVO.setMemo(memo);
			
			bf.close();
			isr.close();
			fis.close();
			
			long parse_endTime=System.currentTimeMillis();
			long parseTime=parse_startTime-parse_endTime;
			log.info("文件：" + localFileName + "解析入库耗时：" + parseTime + "ms");
			
			return ftpFileVO;
		} catch (Exception e) {
			String errormsg = "解析文件发生异常->" + CommonUtils.getMessageByLength(e.getMessage(), 400);
			ftpFileVO.setMemo(errormsg);
			return ftpFileVO;
		} finally {
			if (bf != null) {
				try {
					bf.close();
				} catch (IOException e) {
				}
			}
			if (isr != null) {
				try {
					isr.close();
				} catch (IOException e) {
				}
			}
			
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
				}
			} 
		}
	}

	/**
	 * 判断当日是否是t+1业务的放款日（双休和工作日中的节假日都不放款）
	 * 
	 * @return
	 * @throws BusinessException
	 */
	private boolean isT1LoanDay(String date, String year) throws BusinessException {
		GregorianCalendar calendar = new GregorianCalendar();
		TbWeekend vo = tbWeekEndService.queryWorkDayForWeekend(date, year);
		//周六、周日或者工作日中调休的节假日都不放款
		if (calendar.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.SATURDAY
				|| calendar.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.SUNDAY
				|| !CommonUtils.isEmpty(vo)) {
			return false;
		}
		return true;
	}

	private String[] getT1BillDateListFromDate(String date, String year) throws BusinessException {
		if (!isT1LoanDay(date, year))
			return null;
		
		try {
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			Calendar cal = Calendar.getInstance(); 
			cal.setTime(df.parse(date)); 

			TbBillDateInfo infovo = billDateInfoService.queryBillDateByLoanDateAndType(date, "T1");
			if (infovo != null) {
				return getBillDateListByStr(infovo.getBilldatelist());
			}
			
			if (cal.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.MONDAY) {
				//周一放款：周五、周六、周日三天的明细单对应金额
				return new String[] {
						TimeUtils.getDateBefore(date, 3), TimeUtils.getDateBefore(date, 2), TimeUtils.getDateBefore(date, 1)
				};
			} else if (cal.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.TUESDAY ||
					cal.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.WEDNESDAY ||
					cal.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.THURSDAY ||
					cal.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.FRIDAY) {
				//周二、三、四、五放款：查询前一天的明细单对应金额
				return new String[] {TimeUtils.getDateBefore(date, 1)}; 
			} else if (cal.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.SUNDAY ||
					cal.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.SATURDAY) {
				//周六、日不放款
				return null;
			}
		} catch (ParseException e) {
			throw new BusinessException("data->" + date + "获取放款日期对应的明细单日期出错" + e.getMessage());
		} catch (Exception e) {
			throw new BusinessException("data->" + date + "获取放款日期对应的明细单日期出错" + e.getMessage());
		}
		
		return null;
	}
	
	private String[] getBillDateListByStr(String billdatestr) {
		if (StringUtils.isEmpty(billdatestr))
			return null;
		
		return billdatestr.split(",");
	}


	@Override
	public List<TbFtpFile> selectFtpFileListByCondition(String filetype, Integer downloadflag, Integer dealflag, Integer joinuserid, String startdate, String enddate, Pageable page) throws BusinessException {
		return ((TbFtpFileDao) this.getBaseDao()).selectFtpFileListByCondition(filetype, downloadflag, dealflag, joinuserid, startdate, enddate, page) ;
	}
	

}
